/*
 * Copyright 2011 Shotaro Uchida <fantom@xmaker.mx>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jazzkaffe;

import java.net.ProtocolException;

/**
 * Abstract ZigBee addressing primitive.
 * @author Shotaro Uchida <fantom@xmaker.mx>
 */
public abstract class ZigBeeAddress {

    protected int addressSize;
    protected byte[] mac;

    protected ZigBeeAddress(byte[] mac, int addressSize) {
        this.addressSize = addressSize;
        if (mac == null) {
            this.mac = new byte[addressSize];
            for (int i = 0; i < addressSize; i++) {
                this.mac[i] = 0x00;
            }
        } else {
            this.mac = mac;
        }
    }
    
    /**
     * Get ZigBeeAddress by string representation.
     * 
     * @param address
     * @return IEEEAddress or NetworkAddress.
     * @throws ProtocolException 
     */
    public static ZigBeeAddress getByAddress(String address) throws ProtocolException {
        if ((address.length() % 2) != 0) {
            throw new ProtocolException("Invalid address.");
        }

        int addressSize = (address.length() / 2);
        
        byte[] mac = new byte[addressSize];
        for (int i = 0; i < addressSize; i++) {
            int p = (i * 2);
            mac[i] = (byte) Integer.parseInt(address.substring(p, p + 2), 16);
        }
        
        switch (addressSize) {
        case IEEEAddress.ADDRESS_SIZE:
            return new IEEEAddress(mac);
        case NetworkAddress.ADDRESS_SIZE:
            return new NetworkAddress(mac);
        }
        
        throw new ProtocolException("Invalid address.");
    }
    
    public boolean isUnicast() {
        return !(this instanceof GroupAddress)
                && !(
                    (this instanceof NetworkAddress)
                    && ((NetworkAddress) this).isBroadcast());
    }

    public String toString() {
        String s = "";
        for (int i = 0; i < addressSize; i++) {
            s += toHexString(mac[i]);
        }
        return s;
    }

    public int hashCode() {
        int hash = 7;
        hash = 79 * hash + hashcode(mac);
        return hash;
    }
    
    private static String toHexString(byte b) {
        String hex = Integer.toHexString(b);
        int len = hex.length();
        if (len == 2) {
            return hex;
        } else if (len == 1) {
            return "0" + hex;
        } else {
            return hex.substring(len - 2);
        }
    }
    
    private static int hashcode(byte[] a) {
        if (a == null) {
            return 0;
        }

        int hash = 1;
        for (int i = 0; i < a.length; i++) {
            hash = 31 * hash + a[i];
        }
        
        return hash;
    }

    public boolean equals(Object obj) {
        if (obj instanceof ZigBeeAddress) {
            ZigBeeAddress target = (ZigBeeAddress) obj;
            if (target.addressSize != this.addressSize) {
                return false;
            }
            for (int i = 0; i < addressSize; i++) {
                if (target.mac[i] != this.mac[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    public byte[] array() {
        return mac;
    }
}
